﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using GameLauncher.Utilities;

namespace GameLauncher.ViewModel
{
    public class MainViewModel : INPC
    {
        #region Members
        private Window view;
        private Boolean isAnimating;
        private int objBig;

        private DispatcherTimer dt;
        private int timerTicks;
        private int timerSteps = 1000;
        private Boolean makeItNormal = true;
        #endregion Members

        #region Databinded Members
        private double topLeftHeight;
        private double topLeftWidth;

        private double topRightHeight;
        private double topRightWidth;

        private double bottomLeftHeight;
        private double bottomLeftWidth;

        private double bottomRightHeight;
        private double bottomRightWidth;

        private string currentGame = null;
        private ObservableCollection<string> topLeftGames; // Colours and shapes
        private ObservableCollection<string> topRightGames; // Cars
        private ObservableCollection<string> bottomLeftGames; // Animals
        private ObservableCollection<string> bottomRightGames; // Persons
        #endregion Databinded Members

        #region Command Members
        private ICommand topLeftCommand;
        private ICommand topRightCommand;
        private ICommand bottomLeftCommand;
        private ICommand bottomRightCommand;
        private ICommand launchSelectedGame;
        #endregion Command Members

        #region Constructor
        public MainViewModel(Window window)
        {
            view = window;
            view.SizeChanged += new SizeChangedEventHandler(Resize);

            topLeftCommand = new RelayCommand(e => Animate(1), b => IsNotAnimating());
            topRightCommand = new RelayCommand(e => Animate(2), b => IsNotAnimating());
            bottomLeftCommand = new RelayCommand(e => Animate(3), b => IsNotAnimating());
            bottomRightCommand = new RelayCommand(e => Animate(4), b => IsNotAnimating());

            launchSelectedGame = new RelayCommand(LaunchGame, b => HasSelectedAGame);

            topLeftGames = new ObservableCollection<string>();
            topRightGames = new ObservableCollection<string>();
            bottomLeftGames = new ObservableCollection<string>();
            bottomRightGames = new ObservableCollection<string>();
            PopulateGamesList();

            ((GameLauncher.View.MainWindow)view).games.SelectionChanged += new System.Windows.Controls.SelectionChangedEventHandler(OnGameSelectionChanged);
        }
        #endregion Constructor

        #region Databinded Methods
        public ObservableCollection<string> GamesList
        {
            get
            {
                switch (objBig)
                {
                    case 1:
                        return topLeftGames;
                    case 2:
                        return topRightGames;
                    case 3:
                        return bottomLeftGames;
                    case 4:
                        return bottomRightGames;
                    default:
                        return null;
                }
            }
        }

        public Visibility GameListVisibility
        {
            get
            {
                // if it is an invalid number or not enlarged, make it invisible.
                return (objBig > 0 || objBig < 5) && !makeItNormal ? Visibility.Visible : Visibility.Hidden;
            }
        }

        public Boolean HasSelectedAGame
        {
            get
            {
                return !string.IsNullOrEmpty(currentGame);
            }
        }

        public double TopLeftHeight
        {
            get { return topLeftHeight; }
            set
            {
                if (topLeftHeight == value)
                    return;

                topLeftHeight = value;
                RaisePropertyChanged("TopLeftHeight");
            }
        }
        public double TopLeftWidth
        {
            get { return topLeftWidth; }
            set
            {
                if (topLeftWidth == value)
                    return;

                topLeftWidth = value;
                RaisePropertyChanged("TopLeftWidth");
            }
        }

        public double TopRightHeight
        {
            get { return topRightHeight; }
            set
            {
                if (topRightHeight == value)
                    return;

                topRightHeight = value;
                RaisePropertyChanged("TopRightHeight");
            }
        }
        public double TopRightWidth
        {
            get { return topRightWidth; }
            set
            {
                if (topRightWidth == value)
                    return;

                topRightWidth = value;
                RaisePropertyChanged("TopRightWidth");
            }
        }

        public double BottomLeftHeight
        {
            get { return bottomLeftHeight; }
            set
            {
                if (bottomLeftHeight == value)
                    return;

                bottomLeftHeight = value;
                RaisePropertyChanged("BottomLeftHeight");
            }
        }
        public double BottomLeftWidth
        {
            get { return bottomLeftWidth; }
            set
            {
                if (bottomLeftWidth == value)
                    return;

                bottomLeftWidth = value;
                RaisePropertyChanged("BottomLeftWidth");
            }
        }

        public double BottomRightHeight
        {
            get { return bottomRightHeight; }
            set
            {
                if (bottomRightHeight == value)
                    return;

                bottomRightHeight = value;
                RaisePropertyChanged("BottomRightHeight");
            }
        }
        public double BottomRightWidth
        {
            get { return bottomRightWidth; }
            set
            {
                if (bottomRightWidth == value)
                    return;

                bottomRightWidth = value;
                RaisePropertyChanged("BottomRightWidth");
            }
        }
        #endregion Databinded Methods

        #region Command Methods
        public ICommand TopLeftCommand
        {
            get { return topLeftCommand; }
        }

        public ICommand TopRightCommand
        {
            get { return topRightCommand; }
        }

        public ICommand BottomLeftCommand
        {
            get { return bottomLeftCommand; }
        }

        public ICommand BottomRightCommand
        {
            get { return bottomRightCommand; }
        }

        public ICommand LaunchSelectedGame
        {
            get { return launchSelectedGame; }
        }
        #endregion Command Methods

        #region Methods
        private void PopulateGamesList()
        {
            topLeftGames.Add("SpeedGame");
            topLeftGames.Add("Sequences");

            topRightGames.Add("Move the car out the parking lot");

            bottomLeftGames.Add("Virtual Pet");

            bottomRightGames.Add("Missing Faces");
        }

        public void Animate(object param)
        {
            // 1 == Top left, 2 == Top right, 3 == Bottom left and 4 == Bottom right
            objBig = (int)param;
            isAnimating = true;
            dt = new DispatcherTimer();
            dt.Tick += new EventHandler(Tick);
            dt.Interval = new TimeSpan(9001);

            if (isBig(objBig))
            {
                makeItNormal = true;
                currentGame = string.Empty;
                RaisePropertyChanged("GameListVisibility");
                timerTicks = 0;
            }
            else
            {
                makeItNormal = false;
                timerTicks = timerSteps;
            }

            dt.Start();
        }

        public bool IsNotAnimating()
        {
            return !isAnimating;
        }

        private Boolean isBig(int objID)
        {
            // if true, the objID has been pressed before
            // if false, it hasn't been pressed before or it doesn't exist
            double vHeight = view.Height / 2 - 26; // standard width of a component
            double vWidth = view.Width / 2 - 15; // standard height of a component
            switch (objID)
            {
                case 1:
                    if (TopLeftWidth > vWidth && TopLeftHeight > vHeight)
                        return true;
                    break;
                case 2:
                    if (TopRightWidth > vWidth && TopRightHeight > vHeight)
                        return true;
                    break;
                case 3:
                    if (BottomLeftWidth > vWidth && BottomLeftHeight > vHeight)
                        return true;
                    break;
                case 4:
                    if (BottomRightWidth > vWidth && BottomRightHeight > vHeight)
                        return true;
                    break;
                default:
                    return false;
            }
            return false;
        }

        private Boolean resizeComponent(int objID, double width, double height)
        {
            if ((objID < 1 || objID > 4) || width < 0 || height < 0)
                return false; // if params are invalid
            try
            {
                switch (objID)
                {
                    case 1: // Top Left
                        TopLeftWidth = width;
                        TopLeftHeight = height;
                        break;
                    case 2: // Top Right
                        TopRightWidth = width;
                        TopRightHeight = height;
                        break;
                    case 3: // Bottom Left
                        BottomLeftWidth = width;
                        BottomLeftHeight = height;
                        break;
                    case 4: // Bottom Right
                        BottomRightWidth = width;
                        BottomRightHeight = height;
                        break;
                }
            }
            catch (Exception e)
            {
                //Something went wrong... Obviously...
                Console.WriteLine(e.Message);
                return false;
            }

            return true; // if params are correct
        }

        private void LaunchGame(object param)
        {
            Window gameWindow = null;
            switch (currentGame) // Checks which game needs to be launch with the necessary precautions.
            {
                case "SpeedGame":
                    break;
                case "Sequences":
                    break;
                case "Move the car out the parking lot":
                    gameWindow = new MoveTheCar.View.DifficultyWindow();
                    Window window2 = new MoveTheCar.View.MainWindow();
                    MoveTheCar.ViewModel.MainViewModel viewmodel = new MoveTheCar.ViewModel.MainViewModel(gameWindow, window2);

                    gameWindow.DataContext = viewmodel;
                    window2.DataContext = viewmodel;
                    break;
                case "Virtual Pet":
                    break;
                case "Missing Faces":
                    break;
                default:
                    // Error... Launch geen game
                    break;
            }
            gameWindow.Closed += delegate { view.Show(); };
            gameWindow.Show();
            view.Hide();
        }
        #endregion Methods

        #region Events
        private void Resize(object sender, SizeChangedEventArgs e)
        {
            if (IsNotAnimating()) // Prevents resizing if the buttons are animating.
            {
                if (objBig == 0) // 0 == none is big
                {
                    double cWidth = e.NewSize.Width / 2 - 15;
                    double cHeight = e.NewSize.Height / 2 - 26;

                    for (int i = 1; i < 5; i++)
                        resizeComponent(i, cWidth, cHeight);
                }
                else
                {
                    for (int i = 1; i < 5; i++)
                        resizeComponent(i, 0, 0); //First make everything smaller

                    resizeComponent(objBig, e.NewSize.Width - 25, e.NewSize.Height - 48);
                }
            }
        }

        private void Tick(object sender, EventArgs e)
        {
            if ((timerTicks < 0 && !makeItNormal) || (timerTicks > timerSteps && makeItNormal))
            {
                if (makeItNormal)
                    objBig = 0;

                dt.Stop();
                RaisePropertyChanged("GamesList");
                RaisePropertyChanged("GameListVisibility");
                isAnimating = false;
                return;
            }

            double stepHeight = ((view.Height / 2) - 26) / timerSteps;
            double stepWidth = ((view.Width / 2) - 15) / timerSteps;

            double stepMaxHeight = ((view.Height) - 48) / timerSteps;
            double stepMaxWidth = ((view.Width) - 25) / timerSteps;

            double stepH = stepMaxHeight - stepHeight;
            double stepW = stepMaxWidth - stepWidth;

            for (int i = 1; i < 5; i++)
                resizeComponent(i, stepWidth * timerTicks, stepHeight * timerTicks);

            resizeComponent(objBig, ((view.Width) - 25) - (stepW * timerTicks), ((view.Height) - 48) - (stepH * timerTicks));

            if (makeItNormal)
                timerTicks++;
            else
                timerTicks--;
        }

        /// <summary>
        /// Called when the selection changes in the SurfaceListBox.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        private void OnGameSelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs args)
        {
            // The content of the SelectedItem is a <item>.
            // That is, if it exists and the user didn't deselect.
            string newGame = ((GameLauncher.View.MainWindow)view).games.SelectedItem as string;
            if (newGame == null || newGame == currentGame)
                return;

            // Start the game that was just selected, if the user presses the start button
            currentGame = newGame;
        }
        #endregion Events
    }
}